/*!
 * \file HftLatencyTool.cpp
 * \project	WonderTrader
 *
 * \author Wesley
 * \date 2020/03/30
 * 
 * \brief HFT高频交易延迟测试工具实现文件
 * 
 * \details 本文件实现了HFT高频交易延迟测试工具的完整功能，包括：
 *          - 测试环境的搭建和初始化
 *          - 模拟行情解析器和交易接口
 *          - 测试策略的实现
 *          - 延迟测量和性能统计
 *          - CPU核心绑定优化
 *          
 *          该工具能够准确测量WonderTrader HFT引擎的内部处理延迟，
 *          为系统性能优化提供重要的基准数据。
 */
#include "HftLatencyTool.h"
#include "../WtCore/HftStraContext.h"

#include "../Includes/WTSVariant.hpp"
#include "../Includes/IParserApi.h"
#include "../Includes/ITraderApi.h"
#include "../Includes/WTSContractInfo.hpp"

#include "../WTSTools/WTSLogger.h"
#include "../WTSUtils/WTSCfgLoader.h"

#include "../Share/StrUtil.hpp"
#include "../Share/TimeUtils.hpp"
#include "../Share/CpuHelper.hpp"


USING_NS_WTP;

/*!
 * \brief HFT延迟测试入口函数
 * 
 * \details 创建HFT延迟测试工具实例并执行完整的测试流程：
 *          1. 初始化测试环境
 *          2. 运行延迟测试
 *          3. 输出测试结果
 */
void test_hft()
{
	hft::HftLatencyTool runner;
	runner.init();

	runner.run();
}

namespace hft
{
	/*!
	 * \brief 检查浮点数有效性
	 * 
	 * \details 检查浮点数是否为有效值，将无效值（DBL_MAX、FLT_MAX）转换为0.0
	 * 
	 * \param x 待检查的浮点数
	 * \return double 有效的浮点数值
	 */
	inline double checkValid(double x)
	{
		return ((x == DBL_MAX || x == FLT_MAX) ? 0.0 : x);
	}

	/*!
	 * \brief 时间字符串转换为时间整数
	 * 
	 * \details 将时间字符串（如"10:05:23"）转换为时间整数（如100523）
	 * 
	 * \param strTime 时间字符串，格式为"HH:MM:SS"
	 * \return uint32_t 时间整数，格式为HHMMSS
	 */
	inline uint32_t strToTime(const char* strTime)
	{
		static char str[10] = { 0 };
		const char *pos = strTime;
		int idx = 0;
		auto len = strlen(strTime);
		for (std::size_t i = 0; i < len; i++)
		{
			if (strTime[i] != ':')
			{
				str[idx] = strTime[i];
				idx++;
			}
		}
		str[idx] = '\0';

		return strtoul(str, NULL, 10);
	}

	/*!
	 * \class TestParser
	 * \brief 测试行情解析器类
	 * 
	 * \details 模拟行情解析器，用于生成测试用的行情数据。
	 *          该类实现了IParserApi接口，能够：
	 *          - 生成指定数量的模拟tick数据
	 *          - 测量数据处理的延迟时间
	 *          - 提供性能统计信息
	 */
	class TestParser : public IParserApi
	{
	public:
		/*!
		 * \brief 运行延迟测试
		 * 
		 * \details 生成指定数量的模拟tick数据并发送给HFT引擎，
		 *          同时测量处理延迟：
		 *          1. 创建模拟的tick数据
		 *          2. 设置合约信息和价格数据
		 *          3. 发送给引擎处理
		 *          4. 统计总延迟和平均延迟
		 * 
		 * \param times 测试次数，即生成的tick数量
		 */
		void	run(uint32_t times)
		{
			srand(time(NULL));
			TimeUtils::Ticker ticker;
			for (uint32_t i = 0; i < times; i++)
			{
				// 设置模拟的交易日期和时间
				uint32_t actDate = 20220303;// strtoul("20220303", NULL, 10);
				uint32_t actTime = 100523 * 1000 + 500; //strToTime("10:05:23") * 1000 + 500;

				// 获取测试合约信息
				WTSContractInfo* contract = _bd_mgr->getContract("rb2205", "SHFE");
				if (contract == NULL)
					return;

				// 生成随机价格
				double x = rand();

				WTSCommodityInfo* pCommInfo = contract->getCommInfo();

				// 创建tick数据对象
				WTSTickData* tick = WTSTickData::create("rb2205");
				tick->setContractInfo(contract);

				WTSTickStruct& quote = tick->getTickStruct();
				wt_strcpy(quote.exchg, pCommInfo->getExchg());

				// 设置基本价格信息
				quote.action_date = actDate;
				quote.action_time = actTime;

				quote.price = x;
				quote.open = x;
				quote.high = x;
				quote.low = x;
				quote.total_volume = 0;
				quote.trading_date = 20220303;
				quote.settle_price = x;

				quote.open_interest = 0;

				quote.upper_limit = x;
				quote.lower_limit = x;

				quote.pre_close = x;
				quote.pre_settle = x;
				quote.pre_interest = 0;

				// 设置五档委托卖价
				quote.ask_prices[0] = x;
				quote.ask_prices[1] = x;
				quote.ask_prices[2] = x;
				quote.ask_prices[3] = x;
				quote.ask_prices[4] = x;

				// 设置五档委托买价
				quote.bid_prices[0] = x;
				quote.bid_prices[1] = x;
				quote.bid_prices[2] = x;
				quote.bid_prices[3] = x;
				quote.bid_prices[4] = x;

				// 设置五档委托卖量
				quote.ask_qty[0] = 0;
				quote.ask_qty[1] = 0;
				quote.ask_qty[2] = 0;
				quote.ask_qty[3] = 0;
				quote.ask_qty[4] = 0;

				// 设置五档委托买量
				quote.bid_qty[0] = 0;
				quote.bid_qty[1] = 0;
				quote.bid_qty[2] = 0;
				quote.bid_qty[3] = 0;
				quote.bid_qty[4] = 0;

				// 发送tick数据给引擎处理
				_parser_spi->handleQuote(tick, 0);
				tick->release();
			}
			
			// 计算和输出延迟统计信息
			auto total = ticker.nano_seconds();
			double t2t = total * 1.0 / times;
			WTSLogger::warn("%u ticks simulated in %.0f ns, HftEngine Innner Latency: %.3f ns", times, total*1.0, t2t);
		}

	public:
		/*!
		 * \brief 注册行情回调接口
		 * 
		 * \details 注册行情数据处理回调接口，获取基础数据管理器引用
		 * 
		 * \param listener 行情回调接口指针
		 */
		virtual void registerSpi(IParserSpi* listener) override
		{
			_parser_spi = listener;
			_bd_mgr = listener->getBaseDataMgr();
		}

	private:
		IParserSpi*		_parser_spi;	///< 行情回调接口指针
		IBaseDataMgr*	_bd_mgr;		///< 基础数据管理器指针
	};

	TestParser* theParser = NULL;	///< 全局测试解析器实例

	/*!
	 * \class TestTrader
	 * \brief 测试交易接口类
	 * 
	 * \details 模拟交易接口，用于测试环境中的交易功能。
	 *          该类实现了ITraderApi接口的基本功能。
	 */
	class TestTrader : public ITraderApi
	{
	public:
		/*!
		 * \brief 注册交易回调接口
		 * 
		 * \details 注册交易事件回调接口
		 * 
		 * \param listener 交易回调接口指针
		 */
		virtual void registerSpi(ITraderSpi* listener) override
		{
			_trader_spi = listener;
		}

		/*!
		 * \brief 生成委托编号
		 * 
		 * \details 生成模拟的委托编号用于测试
		 * 
		 * \param buffer 输出缓冲区
		 * \param length 缓冲区长度
		 * \return bool 是否成功生成
		 */
		virtual bool makeEntrustID(char* buffer, int length) override
		{
			wt_strcpy(buffer, "123456");
			return true;
		}

		/*!
		 * \brief 下单接口
		 * 
		 * \details 模拟下单操作，直接返回成功
		 * 
		 * \param eutrust 委托信息
		 * \return int 下单结果，0表示成功
		 */
		virtual int orderInsert(WTSEntrust* eutrust) override
		{
			return 0;
		}

	private:
		ITraderSpi*	_trader_spi;	///< 交易回调接口指针
	};

	/*!
	 * \class TestStrategy
	 * \brief 测试策略类
	 * 
	 * \details 用于延迟测试的简单HFT策略实现。
	 *          该策略主要用于测试引擎的响应性能，不执行实际的交易逻辑。
	 */
	class TestStrategy : public HftStrategy
	{
	public:
		/*!
		 * \brief 构造函数
		 * 
		 * \param id 策略ID
		 */
		TestStrategy(const char* id) : HftStrategy(id) {}

		/*!
		 * \brief 获取策略名称
		 * 
		 * \return const char* 策略名称
		 */
		virtual const char* getName() { return "TestStrategy"; }

		/*!
		 * \brief 获取策略工厂名称
		 * 
		 * \return const char* 策略工厂名称
		 */
		virtual const char* getFactName() { return "TestStrategyFact"; }

		/*!
		 * \brief 策略初始化回调
		 * 
		 * \details 策略初始化时的回调函数，可以在此进行策略参数设置
		 * 
		 * \param ctx HFT策略上下文指针
		 */
		virtual void on_init(IHftStraCtx* ctx) override
		{
			// 订阅测试合约的tick数据
			ctx->stra_sub_ticks("SHFE.rb.2205");
		}

		/*!
		 * \brief tick数据回调
		 * 
		 * \details 接收到tick数据时的处理逻辑，用于测试引擎响应延迟
		 * 
		 * \param ctx HFT策略上下文指针
		 * \param code 合约代码
		 * \param newTick 新的tick数据
		 */
		virtual void on_tick(IHftStraCtx* ctx, const char* code, WTSTickData* newTick)
		{
			// 执行测试买单，用于测试交易延迟
			//ctx->stra_sell("SHFE.rb.2205", 2300, 1, "", HFT_OrderFlag_Nor);
			ctx->stra_buy("SHFE.rb.2205", 2300, 1, "", HFT_OrderFlag_Nor);
		}
	};

	/*!
	 * \brief 构造函数实现
	 * 
	 * \details 初始化HFT延迟测试工具的基本状态
	 */
	HftLatencyTool::HftLatencyTool()
	{
	}

	/*!
	 * \brief 析构函数实现
	 * 
	 * \details 清理HFT延迟测试工具的资源
	 */
	HftLatencyTool::~HftLatencyTool()
	{
	}

	/*!
	 * \brief 初始化测试工具实现
	 * 
	 * \details 完整的初始化流程：
	 *          1. 初始化日志系统
	 *          2. 加载配置文件
	 *          3. 加载基础数据文件（交易时段、品种、合约）
	 *          4. 加载热点规则和动作策略
	 *          5. 获取测试参数（次数、CPU核心）
	 *          6. 初始化各个组件
	 * 
	 * \return bool 初始化是否成功
	 */
	bool HftLatencyTool::init()
	{
		// 初始化日志系统
		WTSLogger::init("logcfg.yaml");

		// 加载配置文件
		WTSVariant* _config = WTSCfgLoader::load_from_file("config.yaml", true);
		if (_config == NULL)
		{
			WTSLogger::log_raw(LL_ERROR, "Loading config file config.yaml failed");
			return false;
		}

		// 加载基础数据文件
		WTSVariant* cfgBF = _config->get("basefiles");
		bool isUTF8 = cfgBF->getBoolean("utf-8");
		
		// 加载交易时段配置
		if (cfgBF->get("session"))
			_bd_mgr.loadSessions(cfgBF->getCString("session"), isUTF8);

		// 加载品种配置
		WTSVariant* cfgItem = cfgBF->get("commodity");
		if (cfgItem)
		{
			if (cfgItem->type() == WTSVariant::VT_String)
			{
				_bd_mgr.loadCommodities(cfgItem->asCString(), isUTF8);
			}
			else if (cfgItem->type() == WTSVariant::VT_Array)
			{
				for (uint32_t i = 0; i < cfgItem->size(); i++)
				{
					_bd_mgr.loadCommodities(cfgItem->get(i)->asCString(), isUTF8);
				}
			}
		}

		// 加载合约配置
		cfgItem = cfgBF->get("contract");
		if (cfgItem)
		{
			if (cfgItem->type() == WTSVariant::VT_String)
			{
				_bd_mgr.loadContracts(cfgItem->asCString(), isUTF8);
			}
			else if (cfgItem->type() == WTSVariant::VT_Array)
			{
				for (uint32_t i = 0; i < cfgItem->size(); i++)
				{
					_bd_mgr.loadContracts(cfgItem->get(i)->asCString(), isUTF8);
				}
			}
		}

		// 加载热点规则
		if (cfgBF->get("hot"))
		{
			_hot_mgr.loadHots(cfgBF->getCString("hot"));
			WTSLogger::log_raw(LL_INFO, "Hot rules loades");
		}

		// 初始化动作策略管理器
		_act_mgr.init("actpolicy.yaml");

		// 获取测试参数
		_times = _config->getUInt32("times");
		WTSLogger::warn_f("{} ticks will be simulated", _times);

		_core = _config->getUInt32("core");
		WTSLogger::warn_f("Testing thread will be bind to core {}", _core);

		// 初始化各个组件
		initEngine(_config->get("env"));
		initModules();
		initStrategies();

		// 释放配置对象
		_config->release();
		return true;
	}

	/*!
	 * \brief 初始化测试策略实现
	 * 
	 * \details 创建和配置测试策略：
	 *          1. 创建HFT策略上下文
	 *          2. 设置测试策略实例
	 *          3. 绑定交易适配器
	 *          4. 添加到HFT引擎管理
	 * 
	 * \return bool 策略初始化是否成功
	 */
	bool HftLatencyTool::initStrategies()
	{
		// 创建HFT策略上下文
		HftStraContext* ctx = new HftStraContext(&_engine, "stra", false);
		ctx->set_strategy(new TestStrategy("stra"));

		// 绑定交易适配器
		TraderAdapterPtr trader = _traders.getAdapter("trader");
		ctx->setTrader(trader.get());
		trader->addSink(ctx);

		// 添加到引擎管理
		_engine.addContext(HftContextPtr(ctx));

		return true;
	}

	/*!
	 * \brief 初始化HFT引擎实现
	 * 
	 * \details 根据配置初始化HFT引擎：
	 *          1. 设置引擎运行环境
	 *          2. 关联各个管理器
	 *          3. 设置适配器管理器
	 * 
	 * \param cfg 引擎配置参数
	 * \return bool 引擎初始化是否成功
	 */
	bool HftLatencyTool::initEngine(WTSVariant* cfg)
	{
		WTSLogger::warn("Trading enviroment initialzied with engine: HFT");
		
		// 初始化HFT引擎
		_engine.init(cfg, &_bd_mgr, &_dt_mgr, &_hot_mgr, NULL);
		_engine.set_adapter_mgr(&_traders);

		return true;
	}

	/*!
	 * \brief 初始化测试模块实现
	 * 
	 * \details 创建和初始化测试所需的模拟模块：
	 *          1. 创建测试行情解析器和适配器
	 *          2. 创建测试交易接口和适配器
	 *          3. 配置适配器管理器
	 * 
	 * \return bool 模块初始化是否成功
	 */
	bool HftLatencyTool::initModules()
	{
		// 创建测试行情解析器
		{
			theParser = new TestParser();
			ParserAdapterPtr adapter(new ParserAdapter);
			adapter->initExt("parser", theParser, &_engine, &_bd_mgr, &_hot_mgr);
			_parsers.addAdapter("parser", adapter);
		}

		// 创建测试交易接口
		{
			TestTrader * tester = new TestTrader();
			TraderAdapterPtr adapter(new TraderAdapter());
			adapter->initExt("trader", tester, &_bd_mgr, &_act_mgr);
			_traders.addAdapter("trader", adapter);
		}

		return true;
	}

	/*!
	 * \brief 运行延迟测试实现
	 * 
	 * \details 启动HFT延迟测试流程：
	 *          1. 绑定指定的CPU核心（如果配置）
	 *          2. 启动行情解析器和交易适配器
	 *          3. 运行HFT引擎
	 *          4. 执行指定次数的模拟测试
	 *          5. 异常处理和资源清理
	 */
	void HftLatencyTool::run()
	{
		// 绑定CPU核心（如果指定）
		if (_core != 0)
		{
			if (!CpuHelper::bind_core(_core - 1))
			{
				WTSLogger::error_f("Binding to core {} failed", _core);
			}
		}

		try
		{
			// 启动各个组件
			_parsers.run();
			_traders.run();

			// 运行HFT引擎
			_engine.run(true);

			// 开始延迟测试
			theParser->run(_times);
		}
		catch (...)
		{
			// 异常处理（静默处理）
		}
	}
}